<?php

namespace doujunyu\utility;

use think\Exception;


/**
 * 图片操作
 * 文件转移 ->copy_file
 * 删除文件 ->del
 * 抠图 ->image_matting
 * 内容转成图片 ->create_text_image
 * 两个图片合并 ->merge_image
 * 网络图片保存到服务器 ->http_image
 * 判断两个图片的相似度  完全一样返回100 差距越大返回的数越低 ->compare_images
 * 创建目录 ->path
 * 更精确的速度控制版本（推荐）->get_to_file
 * 压缩并且下载->get_to_file_zip
 * 
 * private 保存图片到指定格式->saveImage
 * private 创建图片,图片合并的时候生成的空白图片->create_image_from_file
 * Class SerCurl
 * @package App\Service
 */
class SelfUploads
{

    /**文件转移
     * @param string $old_url
     * @param string $group
     * @return array
     */
    public static function copy_file(string $old_url_file, string $new_url, string $new_file_name = ""): array
    {
        $old_url_file = trim($old_url_file, '/');
        if (empty($old_url_file) || !file_exists('./' . $old_url_file)) {
            return ['图片未找到', ''];
        }
        if (empty(trim($new_url, '/'))) {
            return ['移动文件位置不能为空', ''];
        }
        $file_name = $new_file_name ? $new_file_name : basename($old_url_file);
        $url = self::path(trim($new_url, '/')); //路径
        $group_url = $url . $file_name;
        if ($old_url_file != $group_url) {
            if (!copy('./' . $old_url_file, './' . $group_url)) {
                return ['转移失败', ''];
            }
        }
        return ['', $group_url];
    }

    /**删除文件
     */
    public static function del($file): array
    {
        $file_strpos = strpos($file, 'upload');
        if (empty($file_strpos)) {
            return ['文件路径没有找到upload', ''];
        }
        $file_substr = substr($file, $file_strpos);
        if (!file_exists('./' . $file_substr)) {
            return ['文件不存在', ''];
        }
        if (!unlink('.' . $file)) {
            return ['删除失败', ''];
        }
        return ['', ''];
    }

    /**抠图
     */
    public static function image_matting($path, $group)
    {

        $image = file_get_contents($path);

        $info = getimagesize($path);

        $im = imagecreatefromstring($image);

        $width = $info[0];

        $height = $info[1];

        for ($i = 0; $i < $height; $i += 1) {

            for ($j = 0; $j < $width; $j += 1) {

                $rgb = ImageColorAt($im, $j, $i);

                $r = ($rgb >> 16) & 0xFF;

                $g = ($rgb >> 8) & 0xFF;

                $b = $rgb & 0xFF;

                //                echo $r.'.'.$g.'.'.$b.'.='.$rgb.'
                //x='.$j.', y='.$i.'
                //';



                if (intval($r) > 220 && $g > 220 && $b > 220) {

                    $hex = imagecolorallocate($im, 255, 255, 255);

                    imagesetpixel($im, $j, $i, $hex);
                }
            }
        }

        $white = imagecolorallocate($im, 255, 255, 255); //拾取白色

        imagefill($im, 0, 0, $white); //把画布染成白色

        imagecolortransparent($im, $white); //把图片中白色设置为透明色
        $url = self::path($group . DIRECTORY_SEPARATOR . date('Ymd', time())); //路径

        $group_url = $url . rand(111, 222) . '.png';
        imagepng($im, '.' . $group_url); //生成图片
        return ['', $group_url];
    }

    /**内容转成图片
     *$time_fiel = SelfUploads::createTextImage(
     *            '一段文本',//文本
     *            [
     *                'width' => 270,//宽度
     *                'height' => 22,//高度
     *                'font_size' => 18,//字体大小',
     *                'font_weight' => 0,//字体粗细'
     *                'color' => [255, 255, 255],//文字颜色'
     *                'background' => [0, 0, 0],//背景颜色'
     *            ],
     *            'uploads/'.date('YmdHis'),//保存路径
     *        );
     */
    public static function create_text_image($text = '', $style = [], $save_path = '')
    {
        // $font_size = $style['font_size'] ?? 20; //字体大小',
        // $height = $style['height'] ?? 22; //高度
        $font_center = $style['font_center'] ?? 0;
        // 创建纯红色文字图片
        $image = imagecreate($style['width'] ?? 200, $style['height'] ?? 22);
        // 白色背景
        imagecolorallocate($image, $style['background'][0] ?? 255, $style['background'][1] ?? 255, $style['background'][2] ?? 255);
        // 纯红色文字
        $red = imagecolorallocate($image, $style['color'][0] ?? 0, $style['color'][1] ?? 0, $style['color'][2] ?? 0);
        // 添加红色文字
        //图像资源，字体大小，水平位置，垂直位置，要绘制的文本，文字颜色
        // imagestring($image, 18, 0, 0, "2025-10-16 12:32:33身上", $red);
        //linux执行方式
        // $dir_root = $_SERVER['DOCUMENT_ROOT'];
        // $fontOptions = [
        //     $dir_root.'/uploads/fonts/simsun.ttc',    
        //     $dir_root.'/uploads/fonts/msyhbd.ttc',    // 微软雅黑加粗（推荐）
        //     $dir_root.'/uploads/fonts/simhei.ttf',     // 黑体
        //     $dir_root.'/uploads/fonts/simsunb.ttf',    // 宋体加粗
        //     $dir_root.'/uploads/fonts/STHUPO.TTF',     // 华文琥珀（很粗）
        //     $dir_root.'/uploads/fonts/STXINWEI.TTF',   // 华文新魏
        // ];
        // 中文字体文件路径（需要下载中文字体）决定了字体的粗细
        $fontOptions = [
            'C:/Windows/Fonts/simsun.ttc',
            'C:/Windows/Fonts/msyhbd.ttc',    // 微软雅黑加粗（推荐）
            'C:/Windows/Fonts/simhei.ttf',     // 黑体
            'C:/Windows/Fonts/simsunb.ttf',    // 宋体加粗
            'C:/Windows/Fonts/STHUPO.TTF',     // 华文琥珀（很粗）
            'C:/Windows/Fonts/STXINWEI.TTF',   // 华文新魏
        ];

        $fontFile = $fontOptions[$style['font_weight'] ?? 0]; // 或使用其他中文字体

        // 如果字体文件存在，使用 imagettftext
        $fontSize = $style['font_size'] ?? 20;

        // 计算文字位置（居中）
        $bbox = imagettfbbox($fontSize, 0, $fontFile, $text);
        $textWidth = $bbox[2] - $bbox[0];
        $x = 0;
        if ($font_center == 1) {
            $x = (($style['width'] ?? 200) - $textWidth) / 2;
        }
        $y = (($style['font_size'] ?? 20) + (($style['height'] ?? 22) - ($style['font_size'] ?? 20)) / 2); // 调整垂直位置

        //图像资源，字体大小，文字角度，起始X坐标，起始Y坐标，文字颜色，字体文件路径 ，要绘制的文本
        imagettftext($image, $fontSize, 0, $x, $y, $red, $fontFile, $text);
        //是否加粗
        if (isset($style['font_weight']) && $style['font_weight'] > 0) {
            imagettftext($image, $fontSize, 0, $x, $y + $style['font_weight'], $red, $fontFile, $text);
        }


        $filename = $save_path . '.png';
        // 获取目录路径
        $dir = dirname($filename);
        // 如果目录不存在，递归创建目录
        if (!is_dir($dir)) {
            if (!mkdir($dir, 0755, true)) {
                // 目录创建失败处理
                die("无法创建目录: $dir");
            }
        }

        imagepng($image, $filename, 9);
        imagedestroy($image);
        return $filename;
    }

    //两个图片合并
    public static function merge_image($back_image, $childs = [], $save_path = '')
    {
        $back_image_file = self::create_image_from_file($back_image); // 背景图片

        foreach ($childs as $child) {
            $imageB = self::create_image_from_file($child['file']);
            if (!$imageB) {
                continue;
            }

            // 获取图片尺寸
            $widthB = imagesx($imageB);
            $heightB = imagesy($imageB);
            // 将图片B覆盖到背景图片上
            imagecopy($back_image_file, $imageB, $child['width'], $child['height'], 0, 0, $widthB, $heightB);
            imagedestroy($imageB);
        }

        // 获取目录路径
        $dir = dirname($save_path . '.jpg');
        // 如果目录不存在，递归创建目录
        if (!is_dir($dir)) {
            if (!mkdir($dir, 0755, true)) {
                // 目录创建失败处理
                return ["无法创建目录: $dir", ''];
            }
        }


        // 保存或输出图片
        imagejpeg($back_image_file, $save_path . '.jpg', 100);

        // 释放内存
        imagedestroy($back_image_file);
        return ['', $save_path . '.jpg'];
    }

    /**网络图片保存到服务器
     * @throws \Exception
     */
    public static function http_image($img, $group): array
    {
        $date = date('Ymd', time());
        $rand = time() . random_int(1000, 9999);
        $image = file_get_contents($img);
        $url = self::path($group . '/' . $date);
        $img_name = $rand . '.png';
        file_put_contents('.' . $url . $img_name, $image);

        return ['', $url . $img_name];
    }

    /**判断两个图片的相似度  完全一样返回100 差距越大返回的数越低
     * @param $imagePath1
     * @param $imagePath2
     * @return float|int
     */
    public static function compare_images($imagePath1, $imagePath2)
    {
        $image1 = imagecreatefromjpeg($imagePath1);
        $image2 = imagecreatefromjpeg($imagePath2);

        $difference = 0;
        $width = imagesx($image1);
        $height = imagesy($image1);

        for ($x = 0; $x < $width; $x++) {
            for ($y = 0; $y < $height; $y++) {
                $rgb1 = imagecolorat($image1, $x, $y);
                $rgb2 = imagecolorat($image2, $x, $y);

                $r1 = ($rgb1 >> 16) & 0xFF;
                $g1 = ($rgb1 >> 8) & 0xFF;
                $b1 = $rgb1 & 0xFF;

                $r2 = ($rgb2 >> 16) & 0xFF;
                $g2 = ($rgb2 >> 8) & 0xFF;
                $b2 = $rgb2 & 0xFF;

                $difference += abs($r1 - $r2) + abs($g1 - $g2) + abs($b1 - $b2);
            }
        }
        $totalPixels = $width * $height;
        $similarity = ($totalPixels - ($difference / 3)) / $totalPixels * 100;
        return $similarity;
    }

    /**创建目录
     */
    public static function path($path): string
    {
        //     移动到框架应用根目录/public/uploads 目录下
        //    $dir = DIRECTORY_SEPARATOR .$path.DIRECTORY_SEPARATOR ;
        //     移动到框架应用根目录/public/uploads 目录下
        $dir = "/$path/";
        //    if (!is_dir('.'.$dir )) {  #创建目录
        //        mkdir('.'.$dir,0777,true);
        //    }
        if (!is_dir('.' . $dir) && !mkdir($concurrentDirectory = '.' . $dir, 0777, true) && !is_dir($concurrentDirectory)) {
            throw new \RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory));
        }
        return $dir;
    }

    /**更精确的速度控制版本（推荐）
     * @param string $filePath 文件路径
     * @param int $speed 输出速度（字节/秒）
     * 10KB/s = 10240
     * 50KB/s = 51200
     * 100KB/s = 102400
     * 500KB/s = 512000
     * 1MB/s = 1048576
     * @return void
     */
    public static function get_to_file($file, $outputFilename = '', $speed = 1048576)
    {
        // 检查文件是否存在
        if (!file_exists($file)) {
            header('HTTP/1.1 404 Not Found');
            echo "File not found";
            return;
        }

        // 获取原文件的后缀
        $fileExtension = pathinfo($file, PATHINFO_EXTENSION);

        // 设置输出文件名
        if ($outputFilename == '') {
            $outputFilename = pathinfo($file, PATHINFO_FILENAME);
        }

        // 组合最终文件名：输出文件名 + 原文件后缀
        $finalFilename = $outputFilename . ($fileExtension ? '.' . $fileExtension : '');

        // 设置PDF相关的HTTP头
        header("Content-Type: application/octet-stream"); //如果让浏览器知道类型，浏览器会自动渲染，否则是直接下载
        header("Accept-Ranges: bytes");
        header("Content-Disposition: inline; filename=\"" . $finalFilename . "\"");
        header("Cache-Control: private, must-revalidate");

        $size = filesize($file);

        // 处理范围请求（支持断点续传）
        if (isset($_SERVER['HTTP_RANGE'])) {
            header("HTTP/1.1 206 Partial Content");
            list($name, $range) = explode("=", $_SERVER['HTTP_RANGE']);
            list($begin, $end) = explode("-", $range);
            if ($end == 0) $end = $size - 1;
        } else {
            $begin = 0;
            $end = $size - 1;
        }

        header("Content-Length: " . ($end - $begin + 1));
        header("Content-Range: bytes " . $begin . "-" . $end . "/" . $size);

        try {
            $fp = fopen($file, 'rb');
            if (!$fp) {
                throw new \Exception("Cannot open file");
            }
        } catch (\Exception $e) {
            header('HTTP/1.1 500 Internal Server Error');
            echo $e->getMessage();
            return;
        }

        fseek($fp, $begin);

        // 计算每次读取的块大小和休眠时间
        $chunkSize = 8192; // 8KB
        $sleepTime = ($chunkSize / $speed) * 1000000; // 转换为微秒

        $bytesSent = 0;
        $totalBytes = $end - $begin + 1;

        // 清空输出缓冲区
        if (ob_get_level()) {
            ob_end_clean();
        }
        ob_start();

        while (!feof($fp) && $bytesSent < $totalBytes) {
            // 计算本次读取的实际大小
            $readSize = min($chunkSize, $totalBytes - $bytesSent);
            $contents = fread($fp, $readSize);

            echo $contents;
            ob_flush();
            flush();

            $bytesSent += strlen($contents);

            // 如果连接中断则停止
            if (connection_aborted()) {
                break;
            }

            // 控制输出速度
            if ($sleepTime > 0) {
                usleep($sleepTime);
            }
        }

        ob_end_flush();
        fclose($fp);
        exit;
    }

    /**压缩并且下载 
     * $files = [
     *     ['name' => 文件名, 'path' => 文件路径],
     *     ['name' => 文件名, 'path' => 文件路径],
     *     ['name' => 文件名, 'path' => 文件路径],
     * ];
     * $zipFilename = 压缩文件名(不要带后缀，后缀里面自带zip)
     * $speed = 输出速度（字节/秒）
     * 10KB/s = 10240
     * 50KB/s = 51200
     * 100KB/s = 102400
     * 500KB/s = 512000
     * 1MB/s = 1048576
     * 
     */
    public static function get_to_file_zip(array $files, $zipFilename = '', $speed = 51200)
    {
        if (!extension_loaded('zip')) {
            header('HTTP/1.1 500 Internal Server Error');
            echo 'Zip extension not available';
            return false;
        }

        if (!$zipFilename) {
            $zipFilename = 'download_' . date('Ymd_His') . '.zip';
        } else {
            $zipFilename = $zipFilename . '.zip';
        }


        // 设置头信息
        header('Content-Type: application/zip');
        header('Content-Disposition: attachment; filename="' . $zipFilename . '"');
        header('Cache-Control: no-cache, no-store, must-revalidate');
        header('Pragma: no-cache');
        header('Expires: 0');

        $zip = new \ZipArchive();
        $tempZip = tempnam(sys_get_temp_dir(), 'zip');

        if ($zip->open($tempZip, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== TRUE) {
            return false;
        }

        // 添加文件到压缩包
        foreach ($files as $filePath => $downloadName) {
            $file_name = '';
            if (file_exists($downloadName['path'])) {
                if (isset($downloadName['name']) && !empty($downloadName['name'])) {
                    $file_name = $filePath . $downloadName['name'] . '.' . pathinfo($downloadName['path'], PATHINFO_EXTENSION);
                } else {
                    $path = parse_url($downloadName['path'], PHP_URL_PATH);
                    $path_arr = explode('/', $path);
                    // $path_name = explode('.',end($path_arr));
                    // $fileinfo['basename'] = array_shift($path_name);
                    // $fileinfo['filename'] = end($path_arr);
                    $file_name = end($path_arr);
                }
                $zip->addFile($downloadName['path'], $file_name);
            }
        }
        $zip->close();
        //在这里写入限流

        // ==================== 流式输出开始 ====================

        // 获取文件信息
        $fileSize = filesize($tempZip);
        $fileHandle = fopen($tempZip, 'rb');

        if (!$fileHandle) {
            unlink($tempZip);
            return false;
        }

        // 处理断点续传范围请求
        $rangeHeader = $_SERVER['HTTP_RANGE'] ?? '';
        $start = 0;
        $end = $fileSize - 1;

        if ($rangeHeader && preg_match('/bytes=(\d+)-(\d*)/', $rangeHeader, $matches)) {
            // 解析范围请求
            $start = intval($matches[1]);
            $end = isset($matches[2]) && $matches[2] !== '' ? intval($matches[2]) : $fileSize - 1;

            // 设置206部分内容状态码
            header('HTTP/1.1 206 Partial Content');
            header('Content-Range: bytes ' . $start . '-' . $end . '/' . $fileSize);
        } else {
            // 完整文件请求
            header('HTTP/1.1 200 OK');
        }

        // 设置响应头
        header('Content-Type: application/zip');
        header('Content-Disposition: attachment; filename="' . $zipFilename . '"');
        header('Content-Length: ' . ($end - $start + 1));
        header('Accept-Ranges: bytes');
        header('Cache-Control: no-cache, no-store, must-revalidate');
        header('Pragma: no-cache');
        header('Expires: 0');

        // 定位到开始位置
        fseek($fileHandle, $start);

        // ==================== 限流输出逻辑 ====================

        $chunkSize = 8192; // 8KB 每次读取的块大小
        $bytesSent = 0;
        $totalBytesToSend = $end - $start + 1;

        // 计算每次读取后需要休眠的时间（微秒）
        $sleepTimePerChunk = $speed > 0 ? ($chunkSize / $speed) * 1000000 : 0;

        // 清空输出缓冲区确保直接输出
        if (ob_get_level()) {
            ob_end_clean();
        }

        // 流式输出文件内容
        while (!feof($fileHandle) && $bytesSent < $totalBytesToSend) {
            // 计算本次读取的大小
            $bytesToRead = min($chunkSize, $totalBytesToSend - $bytesSent);
            $chunk = fread($fileHandle, $bytesToRead);

            // 输出数据块
            echo $chunk;
            flush();

            // 如果还有输出缓冲区，清空它
            if (ob_get_level() > 0) {
                ob_flush();
            }

            $bytesSent += strlen($chunk);

            // 检查客户端是否断开连接
            if (connection_aborted()) {
                break;
            }

            // 限流：控制输出速度
            if ($sleepTimePerChunk > 0) {
                usleep($sleepTimePerChunk);
            }
        }

        // ==================== 清理资源 ====================

        fclose($fileHandle);
        unlink($tempZip);

        return true;
    }

    /**保存图片到指定格式
     */
    private static function saveImage($image, $savePath, $options = [])
    {
        $quality = isset($options['quality']) ? $options['quality'] : 90;
        $extension = strtolower(pathinfo($savePath, PATHINFO_EXTENSION));

        switch ($extension) {
            case 'jpg':
            case 'jpeg':
                return imagejpeg($image, $savePath, $quality);
            case 'png':
                // PNG 质量参数是 0-9，0 是无压缩
                $pngQuality = 9 - round(($quality / 100) * 9);
                return imagepng($image, $savePath, $pngQuality);
            case 'gif':
                return imagegif($image, $savePath);
            case 'webp':
                if (function_exists('imagewebp')) {
                    return imagewebp($image, $savePath, $quality);
                }
                break;
            default:
                // 默认保存为 JPEG
                return imagejpeg($image, $savePath, $quality);
        }

        return false;
    }

    /**创建图片,图片合并的时候生成的空白图片
     */
    private static function create_image_from_file($filePath)
    {
        if (!file_exists($filePath)) {
            return '';
        }

        // 获取文件头信息来判断格式
        $fileInfo = getimagesize($filePath);
        if (!$fileInfo) {
            return '';
        }

        $mimeType = $fileInfo['mime'];
        $image_file = '';
        switch ($mimeType) {
            case 'image/jpeg':
            case 'image/jpg':
                $image_file = imagecreatefromjpeg($filePath);
                break;
            case 'image/png':
                $image_file =  imagecreatefrompng($filePath);
                if ($image_file) {
                    imagealphablending($image_file, true);
                    imagesavealpha($image_file, true);
                }
                $image_file = $image_file;
                break;
            case 'image/gif':
                $image_file = imagecreatefromgif($filePath);
                break;
            case 'image/webp':
                if (function_exists('imagecreatefromwebp')) {
                    $image_file = imagecreatefromwebp($filePath);
                }
                break;
            default:
                return false;
        }

        return $image_file;
    }
}
